#include "graph.h"

Graph::Graph()
{
}

Graph::Graph(const Graph &g)
{
  this->vectCoord = g.vectCoord;
  this->dist = g.dist;
}

Graph::~Graph()
{
  //vectCoord.clear();
  //dist.clear();
}

Graph* Graph::clone()
{
  return new Graph(*this);
}

void Graph::load(const char *fileName)
{
  std::ifstream f(fileName);

  std::cout << ">> Loading [" << fileName << "]" << std::endl;

  if (f)
  {
    unsigned int numVert;

    f >> numVert;
    vectCoord.resize(numVert);
    for (unsigned int i = 0; i < numVert; i++)
    {
      f >> vectCoord[i].first >> vectCoord[i].second;
    }

    f.close();

    computeDistances();
  }
  else
  {
    std::cout << fileName << " doesn't exist!" << std::endl;
    exit(1);
  }
}

unsigned int Graph::size()
{
  return dist.size();
}

float Graph::distance(unsigned int from, unsigned int to)
{
  return (float)(dist[from][to]);
}

void Graph::computeDistances()
{
  unsigned int numCities = vectCoord.size();
  dist.resize(numCities);
  for (unsigned int i = 0; i < dist.size(); i++)
  {
    dist [i].resize(numCities);
  }

  // Computations.
  for (unsigned int i = 0; i < dist.size(); i++)
  {
    for (unsigned int j = i + 1; j < dist.size(); j ++)
    {
      double distX = (double)(vectCoord [i].first - vectCoord [j].first);
      double distY = (double)(vectCoord [i].second - vectCoord [j].second);
      dist[i][j] = dist[j][i] = (unsigned)(sqrt((float)(distX
              * distX + distY * distY)) + 0.5) ;
    }
  }
}

void Graph::Serialize(edaBuffer &buf, bool pack)
{
  if (pack)
  {
    // First, pack the vectCoord
    unsigned _size = vectCoord.size();
    buf.Pack(&_size, 1);

    std::vector<std::pair <double, double> >::iterator coordIter;
    for (coordIter = vectCoord.begin(); coordIter != vectCoord.end(); coordIter++)
    {
      buf.Pack((double *) &(coordIter->first), 1);
      buf.Pack((double *) &(coordIter->second), 1);
    }

    // Then pack the dist vector (of vector)
    _size = dist.size();
    buf.Pack(&_size, 1);

    std::vector<std::vector<unsigned int> >::iterator distIter;
    for (distIter = dist.begin(); distIter != dist.end(); distIter++)
    {
      // Get the size of each distance vector
      unsigned uiSize = distIter->size();
      buf.Pack(&uiSize, 1);

      std::vector<unsigned int>::iterator uiIter;
      for (uiIter = distIter->begin(); uiIter != distIter->end(); uiIter++)
      {
        // Pack the distance
        buf.Pack((unsigned int *)&(*uiIter), 1);
      }
    }
  }
  else  // Unpack
  {
    unsigned _size;
    // First, unpack the vectCoord
    buf.UnPack(&_size, 1);
    vectCoord.resize(_size);

    for (unsigned i = 0; i < _size; i++)
    {
      double d1, d2;
      std::pair<double, double> coord;
      buf.UnPack(&d1, 1);
      buf.UnPack(&d2, 1);

      coord.first = d1;
      coord.second = d2;
      vectCoord[i] = coord;
    }

    // Then unpack the dist vector
    buf.UnPack(&_size, 1);
    dist.resize(_size);

    for (unsigned int i = 0; i < _size; i++)
    {
      // Get the size of each distance vector
      unsigned int distSize;
      buf.UnPack(&distSize, 1);

      std::vector<unsigned int> dVector;
      dVector.resize(distSize);

      for (unsigned int j = 0; j < distSize; j++)
      {
        unsigned int distance;
        buf.UnPack(&distance, 1);

        dVector[j] = distance;
      }

      dist[i] = dVector;
    }
  }
}

Graph& Graph::operator = (Graph &g)
{
  this->vectCoord = g.vectCoord;
  this->dist = g.dist;

  return g;
}
